[AD] Scalaアプリケーションの開発・保守は合同会社ミルクソフトにお任せください
この記事では、Scala 3(コードネーム:Dotty)にて追加された「交差型」について解説します。
交差型とは「A
かつB
」を表す型
交差型とは、二つの型の性質を同時に満たすような値のもつ型を表します。
&
記号で表します。
例えばA
という型とB
という型があるとき、A & B
と表すと「A
でありかつB
でもある型」という意味になります。
実はScala 2においてもwith
キーワードを使って似たようなものを表せたのですが、これとの違いについては後述します。
交差型は可換で、共変である
交差型は可換です。つまり、B & A
もA & B
も同じ型です。
また、共変でもあります。つまり、C[A] & C[B]
はC[A & B]
です。
典型的には、以下のような表現ができるようになりました。これはコンパイルが通ります。
trait A { def children: List[A] } trait B { def children: List[B] } object Main extends App { trait C extends A with B { def children: List[A & B] } val x: A & B = new C { override def children: List[A & B] = List() // filled temporarily } val ys: List[A & B] = x.children }
def children
の戻り値がList[A & B]
であることに注目してください。
Scala 2系では「複合型with
」で表現していた
交差型ではないですが、Scala 2系には複合型というものがありました(3にもあります)。
複合型はwith
キーワードによって定義していました。
使い方はほぼ&
と同じです。
ただしScala 2.13においては、先ほどの例をwith
で置き換えて同等の表現をしても、コンパイルは通りません。
trait A { def children: List[A] } trait B { def children: List[B] } object Main extends App { trait C extends A with B { def children: List[A with B] } val x: A with B = new C { override def children: List[A with B] = List() } val ys: List[A with B] = x.children // type mismatch; // found : List[B] // required: List[A with B] }
複合型は線形化の都合により共変ではなかったので、A with B
と定義したはずのメソッドの戻り値がB
になってしまっています。
これこそが複合型の限界でした。
複合型(with
)との違い
ただし、Scala 3においてもwith
を使った複合型は存続します。
では、どう違うのか、どう使い分けるのか、という点に疑問が生じると思います。この節ではこれについて深掘りしていきます。
2系のwith
には二つの意味があり、片方を分離独立させたのが&
with
には二つの意味がありました。
- 「複数のトレイトを同時に満たしている値の型」という条件を示す表現
- より抽象的
- クラス定義時に複数個のトレイトの実装をどの順番で線形化するかを指示する表現
- より具体的
抽象度の違うこの両者の識別がわかりにくかったのです。
1.に相当する箇所までもがあたかもB.のように線形化の状態を要求しているかのように見えていました。
1.の部分を分離したのが交差型&
です。
しばらくは移行期間;with
は&
に置換される
Scala 3では、しばらくの間は移行期間として、with
キーワードも使うことができます。
1.のwith
は内部的に&
に置換して解釈されます。
2.のwith
は引き続きwith
として解釈されます。
交差型の導入は何が嬉しいのか
2系までなら型システムの限界で表現できなかったような型を表現できるようになりました。
つまり「型の表現力が増した」ということです。
Scala言語の開発、あるいはある種のライブラリの開発にとっては生産性が高まるため喜ばしいはずです。
Scalaを活用する一般の開発者にとっては、これといって嬉しいことはないかもしれません。
強いて言えば、「with
と書いてあればその箇所で線形化をしている」「&
と書いてある場合にはそこでは線形化していない」というのがはっきり見てわかるようになったのが、一般の開発者としては大きいでしょう。
あるいは、&
は条件演算子でも「かつ」という意味で用いられているため、交差型でも&
を使用することでより読みやすくなった面もあります。